package com.example.messagequeue.mqserver.core;

import com.example.messagequeue.commom.MqException;

import java.util.Arrays;

/*
 *使用这个类，来验证交换机的转发规则
 * 同时也借助这个类验证，bindingKey是否合法
 */
public class Router {
    //bindingKey 的构造规则
    //1.数字， 字母， 下划线
    //2，使用，或者_分割
    //3.允许使用*或者#来替代。如aaa.*.bbb
    public boolean checkBindingKey(String bindingKey){
        if (bindingKey.length() == 0){
            //空字符串，合法情况下，比如在使用direct/fanout交换机的时候，
            return true;
        }
        for (int i = 0; i < bindingKey.length(); i++){
            char ch = bindingKey.charAt(i);
            if (ch >= 'A' && ch <= 'Z'){
                continue;
            }else if(ch >= 'a' && ch <= 'z'){
                continue;
            }else if (ch >= '0' && ch <= '9'){
                continue;
            }else if(ch == '.' || ch == '_' || ch == '*' || ch == '#'){
                continue;
            }else {
                return false;
            }
        }
        String[] words = bindingKey.split("\\.");
        for (String word : words){
            if (word.length() >= 2 && (word.contains("#") || word.contains("*"))){
                return false;
            }
        }
        for (int i = 0; i < words.length - 1; i++){
            if (words[i].equals("#") && words[i + 1].equals("#")){
                return false;
            }else if (words[i].equals("*") && words[i + 1].equals("#")){
                return false;
            }else if (words[i].equals("#") && words[i + 1].equals("*")){
                return false;
            }else {
                ;
            }
        }
        return true;
    }

    //routingKey 的构造规则
    //1.数字， 字母， 下划线
    //2，使用，或者_分割
    public boolean checkRoutingKey(String routingKey){
        if (routingKey.length() == 0){
            //空字符串，合法情况下，比如在使用fanout交换机的时候，routingKey用不上,就可以设定为”“；
            return true;
        }
        for (int i = 0; i < routingKey.length(); i++){
            char ch = routingKey.charAt(i);
            if (ch >= 'A' && ch <= 'Z'){
                continue;
            }else if(ch >= 'a' && ch <= 'z'){
                continue;
            }else if (ch >= '0' && ch <= '9'){
                continue;
            }else if(ch == '.' || ch == '_'){
                continue;
            }else {
                return false;
            }
        }
        return true;
    }

    //用来判定该消息是否可以转发给这个绑定对应的队列
    public boolean route(ExchangeType exchangeType, Binding binding, Message message) throws MqException {
        if (ExchangeType.FANOUT == exchangeType){
            //如果是FANOUT类型，则该类型上所有绑定的队列都需要转发
            return true;
        }else if (ExchangeType.TOPIC == exchangeType){
            //如果是topic类型，规则则要更复杂些
            return routeTopic(binding, message);
        }else {
            throw new MqException("[Router] 交换机类型非法！exchangeType = " + exchangeType);
        }
    }

    private boolean routeTopic(Binding binding, Message message) {
        String[] bindingTokens = binding.getBindingKey().split("\\.");
        String[] routingTokens = message.getRoutingKey().split("\\.");

        int bindingIndex = 0;
        int routingIndex = 0;

        while (bindingIndex < bindingTokens.length && routingIndex < routingTokens.length){
            if (bindingTokens[bindingIndex].equals("*")){
                bindingIndex++;
                routingIndex++;
            } else if (bindingTokens[bindingIndex].equals("#")) {
                bindingIndex++;
                if (bindingIndex == bindingTokens.length){
                    return true;
                }
                routingIndex = findNextMatch(routingTokens, routingIndex, bindingTokens[bindingIndex]);
                if (routingIndex == -1){
                    return false;
                }
                routingIndex++;
                bindingIndex++;
            }else {
                if (!bindingTokens[bindingIndex].equals(routingTokens[routingIndex])){
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            }
        }
        if (routingIndex < routingTokens.length || bindingIndex < bindingTokens.length){
            return false;
        }
        return true;
    }

    private int findNextMatch(String[] routingTokens, int routingIndex, String bindingToken) {
        for (int i = routingIndex; i < routingTokens.length; i++){
            if (routingTokens[i].equals(bindingToken)){
                return i;
            }
        }
        return -1;
    }
}
